home *** CD-ROM | disk | FTP | other *** search
/ Technotools / Technotools (Chestnut CD-ROM)(1993).ISO / lang_c / borcmpad / multipad.c < prev    next >
C/C++ Source or Header  |  1991-07-23  |  32KB  |  1,049 lines

  1. /***************************************************************************
  2.  *                                                                         *
  3.  *  PROGRAM     :  MultiPad modified to demonstrate the use of a status    *
  4.  *                 window in an MDI application.  The changes made to      *
  5.  *                 the Multipad sample application supplied with the       *
  6.  *                 Windows 3.0 SDK are located at the following places:    *
  7.  *                                                                         *
  8.  *                MULTIPAD.C - WM_SIZE case of MPFrameWndProc added to     *
  9.  *                                handle resizing of MDI client and status *
  10.  *                                windows when the frame is resized        *
  11.  *                             StatusWndProc added.  This is the window    *
  12.  *                                procedure for the status window.         *
  13.  *                                                                         *
  14.  *                MPINIT.C -   Class for status window registered in       *
  15.  *                                InitializeApplication                    *
  16.  *                             Status window created in InitializeInstance *
  17.  * 
  18.  *                MULTIPAD.H -  declare hStatWnd, prototype StatusWndProc
  19.  *
  20.  *                MULTIPAD.DEF - EXPORT StatusWndProc
  21.  *
  22.  *                                                                     *
  23.  * ************************************************************************/              
  24.  
  25. /***************************************************************************
  26.  *                                       *
  27.  *  PROGRAM    : MultiPad.c                           *
  28.  *                                       *
  29.  *  PURPOSE    : To give a multi-Notepad demonstration of the new MDI       *
  30.  *          API in Windows 3.0                       *
  31.  *                                       *
  32.  *  FUNCTIONS    : WinMain()          - Calls the initialization function  *
  33.  *                    and processes message loop       *
  34.  *                                       *
  35.  *          MPFrameWndProc()    - Window function for the "frame"    *
  36.  *                    window, which controls the menu    *
  37.  *                    and contains the MDI document       *
  38.  *                    windows as child windows.       *
  39.  *                                       *
  40.  *          MPMDIChildWndProc() - Window function for the individual *
  41.  *                    document windows           *
  42.  *                                       *
  43.  *          InitializeMenu()    - Handles enabling/greying of menu   *
  44.  *                    items according to the app's state.*
  45.  *                                       *
  46.  *          CloseAllChildren    - Destroys all MDI child windows.    *
  47.  *                                       *
  48.  *          CommandHandler()    - Processes the "frame" window's     *
  49.  *                    WM_COMMAND messages.           *
  50.  *                                       *
  51.  *          AboutDlgProc()      - Dialog function for the ubiquitous *
  52.  *                    About.. dialog.            *
  53.  *                                       *
  54.  *          SetWrap()          - Alters word wrapping in the edit   *
  55.  *                    control.               *
  56.  *                                       *
  57.  *          MPError()          - Flashes an error messagebox.       *
  58.  *                                       *
  59.  *          QueryCloseChild     - Prompts for saving current MDI       *
  60.  *                    child window.               *
  61.  *                                       *
  62.  *          QueryCloseAllChildren() - Asks whether it is OK to close *
  63.  *                        down app.               *
  64.  *                                       *
  65.  ***************************************************************************/
  66.  
  67. #include "multipad.h"
  68.  
  69. /* global variables used in this module or among more than one module */
  70. HANDLE hInst;                /* Program instance handle             */
  71. HANDLE hAccel;                /* Main accelerator resource         */
  72. HWND hwndFrame         = NULL;    /* Handle to main window             */
  73. HWND hwndMDIClient     = NULL;    /* Handle to MDI client             */
  74. HWND hwndActive      = NULL;    /* Handle to currently activated child   */
  75. HWND hwndActiveEdit     = NULL;    /* Handle to edit control    */
  76. HWND hStatWnd        = NULL;    /**//* Handle to Status Window  */     
  77. HWND hButton         = NULL;    /**//* Handle to button */     
  78. LONG styleDefault    = 0; /* Default style bits for child windows  */
  79.                     /* The first window is created maximized */
  80.                     /* to resemble Notepad.  Later children  */
  81.                     /* are normal windows.             */
  82. LPSTR lpMenu         = IDMULTIPAD;  /* Contains the resource id of the         */
  83.                     /* current frame menu             */
  84.  
  85.  
  86. /* Forward declarations of helper functions in this module */
  87. VOID NEAR PASCAL InitializeMenu (HANDLE);
  88. VOID NEAR PASCAL CommandHandler (HWND,WORD);
  89. VOID NEAR PASCAL SetWrap (HWND,BOOL);
  90. BOOL NEAR PASCAL QueryCloseAllChildren ( VOID );
  91. int  NEAR PASCAL QueryCloseChild (HWND);
  92.  
  93. /****************************************************************************
  94.  *                                        *
  95.  *  FUNCTION   : WinMain(HANDLE, HANDLE, LPSTR, int)                *
  96.  *                                        *
  97.  *  PURPOSE    : Creates the "frame" window, does some initialization and   *
  98.  *         enters the message loop.                    *
  99.  *                                        *
  100.  ****************************************************************************/
  101. int PASCAL WinMain (HANDLE    hInstance,
  102.             HANDLE    hPrevInstance,
  103.             LPSTR    lpszCmdLine,
  104.             int        nCmdShow)
  105. {
  106.     MSG msg;
  107.  
  108.     hInst = hInstance;
  109.  
  110.     /* If this is the first instance of the app. register window classes */
  111.     if (!hPrevInstance){
  112.     if (!InitializeApplication ())
  113.         return 0;
  114.     }
  115.  
  116.     /* Create the frame and do other initialization */
  117.     if (!InitializeInstance (lpszCmdLine, nCmdShow))
  118.     return 0;
  119.  
  120.     /* Enter main message loop */
  121.     while (GetMessage (&msg, NULL, 0, 0)){
  122.     /* If a keyboard message is for the MDI , let the MDI client
  123.      * take care of it.  Otherwise, check to see if it's a normal
  124.      * accelerator key (like F3 = find next).  Otherwise, just handle
  125.      * the message as usual.
  126.      */
  127.     if ( !TranslateMDISysAccel (hwndMDIClient, &msg) &&
  128.          !TranslateAccelerator (hwndFrame, hAccel, &msg)){
  129.         TranslateMessage (&msg);
  130.         DispatchMessage (&msg);
  131.     }
  132.     }
  133.     return 0;
  134. }
  135.  
  136. /****************************************************************************
  137.  *                                        *
  138.  *  FUNCTION   : MPFrameWndProc (hwnd, msg, wParam, lParam )            *
  139.  *                                        *
  140.  *  PURPOSE    : The window function for the "frame" window, which controls *
  141.  *         the menu and encompasses all the MDI child windows. Does   *
  142.  *         the major part of the message processing. Specifically, in *
  143.  *         response to:                            *
  144.  *                                        *
  145.  *             WM_CREATE        : Creates and displays the "frame". *
  146.  *                                        *
  147.  *             WM_INITMENU    : Sets up the state of the menu.    *
  148.  *                                        *
  149.  *             WM_WININICHANGE &  : If default printer characteristics*
  150.  *             WM_DEVMODECHANGE      have been changed, reinitialises  *
  151.  *                      printer DC.                *
  152.  *                                        *
  153.  *             WM_COMMAND     : Passes control to a command-        *
  154.  *                      handling function.            *
  155.  *                                        *
  156.  *             WM_CLOSE        : Quits the app. if all the child   *
  157.  *                      windows agree.            *
  158.  *                                        *
  159.  *             WM_QUERYENDSESSION : Checks that all child windows     *
  160.  *                      agree to quit.            *
  161.  *                                        *
  162.  *             WM_DESTROY     : Destroys frame window and quits   *
  163.  *                      app.                    *
  164.  *                                        *
  165.  ****************************************************************************/
  166. LONG FAR PASCAL MPFrameWndProc ( hwnd, msg, wParam, lParam )
  167.  
  168. register HWND     hwnd;
  169. WORD         msg;
  170. register WORD     wParam;
  171. LONG         lParam;
  172.  
  173. {
  174. static WORD wCharHeight;    /**/ /*  for the height of status window */
  175.     switch (msg){
  176.     case WM_CREATE:{
  177.  
  178.         CLIENTCREATESTRUCT ccs;
  179.         HDC hDC;
  180.             TEXTMETRIC  tm;
  181.             
  182. /**/
  183.             hDC = GetDC(hwnd);
  184.             GetTextMetrics(hDC, &tm);
  185.             wCharHeight = tm.tmHeight + tm.tmExternalLeading + 4;
  186.             ReleaseDC(hwnd, hDC);
  187. /**/
  188.         /* Find window menu where children will be listed */
  189.         ccs.hWindowMenu = GetSubMenu (GetMenu(hwnd),WINDOWMENU);
  190.         ccs.idFirstChild = IDM_WINDOWCHILD;
  191.  
  192.         /* Create the MDI client filling the client area */
  193.         hwndMDIClient = CreateWindow ("mdiclient",
  194.                       NULL,
  195.                       WS_CHILD | WS_CLIPCHILDREN |
  196.                       WS_VSCROLL | WS_HSCROLL,
  197.                       0,
  198.                       0,
  199.                       0,
  200.                       0,
  201.                       hwnd,
  202.                       0xCAC,
  203.                       hInst,
  204.                       (LPSTR)&ccs);
  205.  
  206.  
  207.         ShowWindow (hwndMDIClient,SW_SHOW);
  208.  
  209.         hButton = CreateWindow( "button", "Bogus row of buttons",
  210.                                     WS_CHILD,
  211.                                     0,0,
  212.                                     150,34,
  213.                                     hwnd,
  214.                                     NULL,
  215.                                     hInst,
  216.                                     NULL
  217.                                 );    
  218.  
  219.         ShowWindow (hButton,SW_SHOW);
  220.         
  221.         /* Check if printer can be initialized */
  222.         if ((hDC = GetPrinterDC ()) != (HDC)0){
  223.         DeleteDC (hDC);
  224.         }
  225.  
  226.         break;
  227.     }
  228.  
  229.     case WM_INITMENU:
  230.         /* Set up the menu state */
  231.         InitializeMenu ((HMENU)wParam);
  232.         break;
  233.  
  234.     case WM_WININICHANGE:
  235.     case WM_DEVMODECHANGE:{
  236.  
  237.         /*    If control panel changes default printer characteristics,
  238.          *    reinitialize our printer information...
  239.          */
  240.         HDC hdc;
  241.  
  242.         if ((hdc = GetPrinterDC ()) != (HDC)0){
  243.         DeleteDC (hdc);
  244.         }
  245.         break;
  246.     }
  247.  
  248. /**/
  249.         /* When the Frame Window is resized, the MDI client window and
  250.         /  the status window must be resized as well.  The MDI Client is
  251.         /  resized to leave room at the bottom of the frame window, and
  252.         /  the status window is resized to reflect any change in width
  253.         /  of the Frame window.
  254.         */
  255.  
  256.         case WM_SIZE:
  257.  
  258.             MoveWindow(hwndMDIClient, 0, 34,
  259.                        LOWORD(lParam), HIWORD(lParam)-wCharHeight - 34, TRUE);
  260.             MoveWindow(hButton, 0, 0, LOWORD(lParam), 34, TRUE);
  261.             InvalidateRect( hButton, NULL, TRUE );
  262.             MoveWindow(hStatWnd, -1, HIWORD(lParam)-wCharHeight,
  263.                        LOWORD(lParam)+ 2, wCharHeight + 1, TRUE);
  264.             InvalidateRect( hStatWnd, NULL, TRUE );        
  265.  
  266.             break;
  267. /**/
  268.     case WM_COMMAND:
  269.         /* Direct all menu selection or accelerator commands to another
  270.          * function
  271.          */
  272.         CommandHandler (hwnd,wParam);
  273.         break;
  274.  
  275.     case WM_CLOSE:
  276.         /* don't close if any children cancel the operation */
  277.         if (!QueryCloseAllChildren ())
  278.         break;
  279.         DestroyWindow (hwnd);
  280.         break;
  281.  
  282.     case WM_QUERYENDSESSION:
  283.         /*    Before session ends, check that all files are saved */
  284.         return QueryCloseAllChildren ();
  285.  
  286.     case WM_DESTROY:
  287.         PostQuitMessage (0);
  288.         break;
  289.  
  290.     default:
  291.         /*    use DefFrameProc() instead of DefWindowProc() since there
  292.          *    are things that have to be handled differently because of MDI
  293.          */
  294.         return DefFrameProc (hwnd,hwndMDIClient,msg,wParam,lParam);
  295.     }
  296.     return 0;
  297. }
  298.  
  299. /****************************************************************************
  300.  *                                        *
  301.  *  FUNCTION   : MPMDIWndProc ( hwnd, msg, wParam, lParam )            *
  302.  *                                        *
  303.  *  PURPOSE    : The window function for the individual document windows,   *
  304.  *         each of which has a "note". Each of these windows contain  *
  305.  *         one multi-line edit control filling their client area.     *
  306.  *         In response to the following:                    *
  307.  *                                        *
  308.  *             WM_CREATE        : Creates & diplays an edit control *
  309.  *                      and does some initialization.     *
  310.  *                                        *
  311.  *             WM_MDIACTIVATE    : Activates/deactivates the child.  *
  312.  *                                        *
  313.  *             WM_SETFOCUS    : Sets focus on the edit control.   *
  314.  *                                        *
  315.  *             WM_SIZE        : Resizes the edit control.        *
  316.  *                                        *
  317.  *             WM_COMMAND     : Processes some of the edit        *
  318.  *                      commands, saves files and alters  *
  319.  *                      the edit wrap state.            *
  320.  *                                        *
  321.  *             WM_CLOSE        : Closes child if it is ok to do so.*
  322.  *                                        *
  323.  *             WM_QUERYENDSESSION : Same as above.            *
  324.  *                                        *
  325.  ****************************************************************************/
  326.  
  327. LONG FAR PASCAL MPMDIChildWndProc ( hwnd, msg, wParam, lParam )
  328.  
  329. register HWND    hwnd;
  330. WORD        msg;
  331. register WORD    wParam;
  332. LONG        lParam;
  333.  
  334. {
  335.     HWND hwndEdit;
  336.  
  337.     switch (msg){
  338.     case WM_CREATE:
  339.         /* Create an edit control */
  340.         hwndEdit = CreateWindow ("edit",
  341.                      NULL,
  342.                      WS_CHILD|WS_HSCROLL|WS_MAXIMIZE|WS_VISIBLE|WS_VSCROLL|ES_AUTOHSCROLL|ES_AUTOVSCROLL|ES_MULTILINE,
  343.                      0,
  344.                      0,
  345.                      0,
  346.                      0,
  347.                      hwnd,
  348.                      ID_EDIT,
  349.                      hInst,
  350.                      NULL);
  351.  
  352.         /* Remember the window handle and initialize some window attributes */
  353.         SetWindowWord (hwnd, GWW_HWNDEDIT, (WORD)hwndEdit);
  354.         SetWindowWord (hwnd, GWW_CHANGED, FALSE);
  355.         SetWindowWord (hwnd, GWW_WORDWRAP, FALSE);
  356.         SetWindowWord (hwnd, GWW_UNTITLED, TRUE);
  357.         SetFocus (hwndEdit);
  358.         break;
  359.  
  360.     case WM_MDIACTIVATE:
  361.         /* If we're activating this child, remember it */
  362.         if (wParam){
  363.         hwndActive     = hwnd;
  364.         hwndActiveEdit = (HWND)GetWindowWord (hwnd, GWW_HWNDEDIT);
  365.         }
  366.         else{
  367.         hwndActive     = NULL;
  368.         hwndActiveEdit = NULL;
  369.         }
  370.         break;
  371.  
  372.     case WM_QUERYENDSESSION:
  373.         /* Prompt to save the child */
  374.         return !QueryCloseChild (hwnd);
  375.  
  376.     case WM_CLOSE:
  377.         /* If its OK to close the child, do so, else ignore */
  378.         if (QueryCloseChild(hwnd))
  379.         goto CallDCP;
  380.         else
  381.         break;
  382.  
  383.     case WM_SIZE:{
  384.         RECT rc;
  385.  
  386.         /* On creation or resize, size the edit control. */
  387.         hwndEdit = GetWindowWord (hwnd, GWW_HWNDEDIT);
  388.         GetClientRect (hwnd, &rc);
  389.         MoveWindow (hwndEdit,
  390.             rc.left,
  391.             rc.top,
  392.             rc.right-rc.left,
  393.             rc.bottom-rc.top,
  394.             TRUE);
  395.         goto CallDCP;
  396.     }
  397.  
  398.     case WM_SETFOCUS:
  399.         SetFocus (GetWindowWord (hwnd, GWW_HWNDEDIT));
  400.         break;
  401.  
  402.     case WM_COMMAND:
  403.         switch (wParam){
  404.         case ID_EDIT:
  405.             switch (HIWORD(lParam)){
  406.             case EN_CHANGE:
  407.  
  408.                 /* If the contents of the edit control have changed,
  409.                    set the changed flag
  410.                  */
  411.                 SetWindowWord (hwnd, GWW_CHANGED, TRUE);
  412.                 break;
  413.  
  414.             case EN_ERRSPACE:
  415.                 /* If the control is out of space, honk */
  416.                 MessageBeep (0);
  417.                 break;
  418.  
  419.             default:
  420.                 goto CallDCP;
  421.             }
  422.             break;
  423.  
  424.         case IDM_FILESAVE:
  425.             /* If empty file, ignore save */
  426.             if (GetWindowWord(hwnd, GWW_UNTITLED)
  427.              && !ChangeFile(hwnd))
  428.             break;
  429.  
  430.             /* Save the contents of the edit control and reset the
  431.              * changed flag
  432.              */
  433.             SaveFile (hwnd);
  434.             SetWindowWord (hwnd, GWW_CHANGED, FALSE);
  435.             break;
  436.  
  437.         case IDM_EDITWRAP: {
  438.             int fWrap = GetWindowWord (hwnd, GWW_WORDWRAP);
  439.  
  440.             /* Set the wrap state, or report it */
  441.             if (LOWORD (lParam)){
  442.             fWrap = !fWrap;
  443.             SetWrap (hwnd, fWrap);
  444.             }
  445.  
  446.             /* return wrap state */
  447.             return fWrap;
  448.         }
  449.  
  450.         default:
  451.             goto CallDCP;
  452.         }
  453.         break;
  454.  
  455.     default:
  456. CallDCP:
  457.         /* Again, since the MDI default behaviour is a little different,
  458.          * call DefMDIChildProc instead of DefWindowProc()
  459.          */
  460.         return DefMDIChildProc (hwnd, msg, wParam, lParam);
  461.     }
  462.     return FALSE;
  463. }
  464.  
  465. /**/
  466. /****************************************************************************
  467.  *                                                                          *
  468.  *  FUNCTION   : StatusWndProc ( hwnd, msg, wParam, lParam )                *
  469.  *                                                                          *
  470.  *  PURPOSE    : The window function for the status windows                 *
  471.  *                                                                          *
  472.  *                                                                          *
  473.  *                   WM_PAINT  : Paints the frame window's dimensions on the*
  474.  *                               status window's client area.               *
  475.  *                                                                          *
  476.  ****************************************************************************/
  477.  
  478.  
  479.  
  480. long FAR PASCAL StatusWndProc(hWnd, message, wParam, lParam)
  481. HWND hWnd;                              /* window handle                   */
  482. unsigned message;                       /* type of message                 */
  483. WORD wParam;                            /* additional information          */
  484. LONG lParam;                            /* additional information          */
  485. {
  486.    switch (message) {
  487.         case WM_CREATE:
  488.     {
  489.     HDC hDC;
  490.  
  491.     hDC = GetDC( hWnd );
  492.     SetBkMode( hDC, TRANSPARENT );
  493.     ReleaseDC( hWnd, hDC );
  494.     }
  495.     break;
  496.     
  497.        case WM_PAINT:
  498.            {
  499.            PAINTSTRUCT ps;
  500.            RECT        rMainWnd;
  501.            char        szBuf[255];
  502.  
  503.            BeginPaint(hWnd,&ps);
  504.            GetClientRect( GetParent( hWnd ),&rMainWnd);
  505.            wsprintf(szBuf,"Main Window Client Area: top: %d left: %d bottom: %d right: %d",
  506.                     rMainWnd.top,rMainWnd.left,rMainWnd.bottom,rMainWnd.right);
  507.            TextOut(ps.hdc,0,2,szBuf,lstrlen(szBuf));
  508.            EndPaint(hWnd,&ps);
  509.            }
  510.            break;
  511.  
  512.        default:                        /* Passes it on if unproccessed    */
  513.            return (DefWindowProc(hWnd, message, wParam, lParam));
  514.    }
  515.  
  516.    return (NULL);
  517.  
  518. }
  519. /**/
  520.  
  521.  
  522. /****************************************************************************
  523.  *                                        *
  524.  *  FUNCTION   : AboutDlgProc ( hwnd, msg, wParam, lParam )            *
  525.  *                                        *
  526.  *  PURPOSE    : Dialog function for the About MultiPad... dialog.        *
  527.  *                                        *
  528.  ****************************************************************************/
  529. BOOL FAR PASCAL AboutDlgProc ( hwnd, msg, wParam, lParam )
  530. HWND          hwnd;
  531. register WORD msg;
  532. register WORD wParam;
  533. LONG          lParam;
  534. {
  535.     switch (msg){
  536.     case WM_INITDIALOG:
  537.         /* nothing to initialize */
  538.         break;
  539.  
  540.     case WM_COMMAND:
  541.         switch (wParam){
  542.         case IDOK:
  543.         case IDCANCEL:
  544.             EndDialog(hwnd, 0);
  545.             break;
  546.  
  547.         default:
  548.             return FALSE;
  549.         }
  550.         break;
  551.  
  552.     default:
  553.         return FALSE;
  554.     }
  555.  
  556.     return TRUE;
  557. }
  558.  
  559. /****************************************************************************
  560.  *                                        *
  561.  *  FUNCTION   : Initializemenu ( hMenu )                    *
  562.  *                                        *
  563.  *  PURPOSE    : Sets up greying, enabling and checking of main menu items  *
  564.  *         based on the app's state.                                  *
  565.  *                                        *
  566.  ****************************************************************************/
  567. VOID NEAR PASCAL InitializeMenu ( hmenu )
  568. register HANDLE hmenu;
  569. {
  570.     register WORD status;
  571.     int       i;
  572.     long      l;
  573.  
  574.     /* Is there any active child to talk to? */
  575.     if (hwndActiveEdit){
  576.     /* If edit control can respond to an undo request, enable the
  577.      * undo selection.
  578.      */
  579.     if (SendMessage (hwndActiveEdit, EM_CANUNDO, 0, 0L))
  580.         status = MF_ENABLED;
  581.     else
  582.         status = MF_GRAYED;
  583.     EnableMenuItem (hmenu, IDM_EDITUNDO, status);
  584.  
  585.     /* If edit control is non-empty, allow cut/copy/clear */
  586.     l      = SendMessage (hwndActiveEdit, EM_GETSEL, 0, 0L);
  587.     status = (HIWORD(l) == LOWORD(l)) ? MF_GRAYED : MF_ENABLED;
  588.     EnableMenuItem (hmenu, IDM_EDITCUT, status);
  589.     EnableMenuItem (hmenu, IDM_EDITCOPY, status);
  590.     EnableMenuItem (hmenu, IDM_EDITCLEAR, status);
  591.  
  592.     status=MF_GRAYED;
  593.     /* If the clipboard contains some CF_TEXT data, allow paste */
  594.     if (OpenClipboard (hwndFrame)){
  595.         int wFmt = 0;
  596.  
  597.         while ((wFmt = EnumClipboardFormats (wFmt)) != 0)
  598.         if (wFmt == CF_TEXT){
  599.             status = MF_ENABLED;
  600.             break;
  601.         }
  602.  
  603.         CloseClipboard ();
  604.     }
  605.     EnableMenuItem (hmenu, IDM_EDITPASTE, status);
  606.  
  607.     /* Set the word wrap state for the window */
  608.     if ((WORD) SendMessage (hwndActive, WM_COMMAND, IDM_EDITWRAP, 0L))
  609.         status = MF_CHECKED;
  610.     else
  611.         status = MF_UNCHECKED;
  612.     CheckMenuItem (hmenu, IDM_EDITWRAP, status);
  613.  
  614.     /* Enable search menu items only if there is a search string */
  615.     if (*szSearch)
  616.         status = MF_ENABLED;
  617.     else
  618.         status = MF_GRAYED;
  619.     EnableMenuItem (hmenu, IDM_SEARCHNEXT, status);
  620.     EnableMenuItem (hmenu, IDM_SEARCHPREV, status);
  621.  
  622.     /* Enable File/Print only if a printer is available */
  623.     status = iPrinter ? MF_ENABLED : MF_GRAYED;
  624.     EnableMenuItem (hmenu, IDM_FILEPRINT, status);
  625.  
  626.     /* select all and wrap toggle always enabled */
  627.     status = MF_ENABLED;
  628.     EnableMenuItem(hmenu, IDM_EDITSELECT, status);
  629.     EnableMenuItem(hmenu, IDM_EDITWRAP, status);
  630.     EnableMenuItem(hmenu, IDM_SEARCHFIND, status);
  631.     }
  632.     else {
  633.     /* There are no active child windows */
  634.     status = MF_GRAYED;
  635.  
  636.     /* No active window, so disable everything */
  637.     for (i = IDM_EDITFIRST; i <= IDM_EDITLAST; i++)
  638.         EnableMenuItem (hmenu, i, status);
  639.  
  640.     CheckMenuItem (hmenu, IDM_EDITWRAP, MF_UNCHECKED);
  641.  
  642.     for (i = IDM_SEARCHFIRST; i <= IDM_SEARCHLAST; i++)
  643.         EnableMenuItem (hmenu, i, status);
  644.  
  645.     EnableMenuItem (hmenu, IDM_FILEPRINT, status);
  646.  
  647.     }
  648.  
  649.     /* The following menu items are enabled if there is an active window */
  650.     EnableMenuItem (hmenu, IDM_FILESAVE, status);
  651.     EnableMenuItem (hmenu, IDM_FILESAVEAS, status);
  652.     EnableMenuItem (hmenu, IDM_WINDOWTILE, status);
  653.     EnableMenuItem (hmenu, IDM_WINDOWCASCADE, status);
  654.     EnableMenuItem (hmenu, IDM_WINDOWICONS, status);
  655.     EnableMenuItem (hmenu, IDM_WINDOWCLOSEALL, status);
  656.  
  657.     /* Allow printer setup only if printer driver supports device initialization */
  658.     if (iPrinter < 2)
  659.     status = MF_GRAYED;
  660.     EnableMenuItem ( hmenu, IDM_FILESETUP, status);
  661.  
  662. }
  663.  
  664. /****************************************************************************
  665.  *                                        *
  666.  *  FUNCTION   : CloseAllChildren ()                        *
  667.  *                                        *
  668.  *  PURPOSE    : Destroys all MDI child windows.                *
  669.  *                                        *
  670.  ****************************************************************************/
  671. VOID NEAR PASCAL CloseAllChildren ()
  672. {
  673.     register HWND hwndT;
  674.  
  675.     /* hide the MDI client window to avoid multiple repaints */
  676.     ShowWindow(hwndMDIClient,SW_HIDE);
  677.  
  678.     /* As long as the MDI client has a child, destroy it */
  679.     while ((hwndT = GetWindow (hwndMDIClient, GW_CHILD)) != (HWND)0){
  680.  
  681.     /* Skip the icon title windows */
  682.     while (hwndT && GetWindow (hwndT, GW_OWNER))
  683.         hwndT = GetWindow (hwndT, GW_HWNDNEXT);
  684.  
  685.     if (!hwndT)
  686.         break;
  687.  
  688.     SendMessage (hwndMDIClient, WM_MDIDESTROY, (WORD)hwndT, 0L);
  689.     }
  690. }
  691.  
  692. /****************************************************************************
  693.  *                                        *
  694.  *  FUNCTION   : CommandHandler ()                        *
  695.  *                                        *
  696.  *  PURPOSE    : Processes all "frame" WM_COMMAND messages.            *
  697.  *                                        *
  698.  ****************************************************************************/
  699. VOID NEAR PASCAL CommandHandler ( hwnd, wParam )
  700. register HWND hwnd;
  701. register WORD wParam;
  702.  
  703. {
  704.     switch (wParam){
  705.     case IDM_FILENEW:
  706.         /* Add a new, empty MDI child */
  707.         AddFile (NULL);
  708.         break;
  709.  
  710.     case IDM_FILEOPEN:
  711.         ReadFile (hwnd);
  712.         break;
  713.  
  714.     case IDM_FILESAVE:
  715.         /* Save the active child MDI */
  716.         SendMessage (hwndActive, WM_COMMAND, IDM_FILESAVE, 0L);
  717.         break;
  718.  
  719.     case IDM_FILESAVEAS:
  720.         /* Save active child MDI under another name */
  721.         if (ChangeFile (hwndActive))
  722.         SendMessage (hwndActive, WM_COMMAND, IDM_FILESAVE, 0L);
  723.         break;
  724.  
  725.     case IDM_FILEPRINT:
  726.         /* Print the active child MDI */
  727.         PrintFile (hwndActive);
  728.         break;
  729.  
  730.     case IDM_FILESETUP:
  731.         /* Set up the printer environment for this app */
  732.         GetInitializationData (hwnd);
  733.         break;
  734.  
  735.     case IDM_FILEMENU:{
  736.  
  737.           /* lengthen / shorten the size of the MDI menu */
  738.           HMENU hMenu;
  739.           HMENU hWindowMenu;
  740.           int i;
  741.  
  742.           if (lpMenu == IDMULTIPAD){
  743.           lpMenu = IDMULTIPAD2;
  744.           i     = SHORTMENU;
  745.           }
  746.           else{
  747.           lpMenu = IDMULTIPAD;
  748.           i     = WINDOWMENU;
  749.           }
  750.  
  751.           hMenu = LoadMenu (hInst, lpMenu);
  752.           hWindowMenu = GetSubMenu (hMenu, i);
  753.  
  754.           /* Set the new menu */
  755.           hMenu = (HMENU)SendMessage (hwndMDIClient,
  756.                       WM_MDISETMENU,
  757.                       0,
  758.                       MAKELONG(hMenu,hWindowMenu));
  759.  
  760.           DestroyMenu (hMenu);
  761.           DrawMenuBar (hwndFrame);
  762.           break;
  763.     }
  764.  
  765.     case IDM_FILEEXIT:
  766.         /* Close Multipad */
  767.         SendMessage (hwnd, WM_CLOSE, 0, 0L);
  768.         break;
  769.  
  770.     case IDM_HELPABOUT:{
  771.         /* Bring up the ubiquitous Ego box */
  772.         FARPROC lpfn;
  773.  
  774.         lpfn = MakeProcInstance(AboutDlgProc, hInst);
  775.         DialogBox (hInst, IDD_ABOUT, hwnd, lpfn);
  776.         FreeProcInstance (lpfn);
  777.         break;
  778.     }
  779.  
  780.     /* The following are edit commands. Pass these off to the active
  781.      * child's edit control window.
  782.      */
  783.     case IDM_EDITCOPY:
  784.         SendMessage (hwndActiveEdit, WM_COPY, 0, 0L);
  785.         break;
  786.  
  787.     case IDM_EDITPASTE:
  788.         SendMessage (hwndActiveEdit, WM_PASTE, 0, 0L);
  789.         break;
  790.  
  791.     case IDM_EDITCUT:
  792.         SendMessage (hwndActiveEdit, WM_CUT, 0, 0L);
  793.         break;
  794.  
  795.     case IDM_EDITCLEAR:
  796.         SendMessage (hwndActiveEdit, EM_REPLACESEL, 0,( LONG)(LPSTR)"");
  797.         break;
  798.  
  799.     case IDM_EDITSELECT:
  800.         SendMessage (hwndActiveEdit, EM_SETSEL, 0, MAKELONG(0, 0xe000));
  801.         break;
  802.  
  803.     case IDM_EDITUNDO:
  804.         SendMessage (hwndActiveEdit, EM_UNDO, 0, 0L);
  805.         break;
  806.  
  807.     case IDM_EDITWRAP:
  808.         SendMessage (hwndActive, WM_COMMAND, IDM_EDITWRAP, 1L);
  809.         break;
  810.  
  811.     case IDM_SEARCHFIND:
  812.         /* Put up the find dialog box */
  813.         Find ();
  814.         break;
  815.  
  816.     case IDM_SEARCHNEXT:
  817.         /* Find next occurence */
  818.         FindNext ();
  819.         break;
  820.  
  821.     case IDM_SEARCHPREV:
  822.         /* Find previous occurence */
  823.         FindPrev ();
  824.         break;
  825.  
  826.     /* The following are window commands - these are handled by the
  827.      * MDI Client.
  828.      */
  829.     case IDM_WINDOWTILE:
  830.         /* Tile MDI windows */
  831.         SendMessage (hwndMDIClient, WM_MDITILE, 0, 0L);
  832.         break;
  833.  
  834.     case IDM_WINDOWCASCADE:
  835.         /* Cascade MDI windows */
  836.         SendMessage (hwndMDIClient, WM_MDICASCADE, 0, 0L);
  837.         break;
  838.  
  839.     case IDM_WINDOWICONS:
  840.         /* Auto - arrange MDI icons */
  841.         SendMessage (hwndMDIClient, WM_MDIICONARRANGE, 0, 0L);
  842.         break;
  843.  
  844.     case IDM_WINDOWCLOSEALL:
  845.         /* Abort operation if something is not saved */
  846.         if (!QueryCloseAllChildren())
  847.         break;
  848.  
  849.         CloseAllChildren();
  850.  
  851.         /* Show the window since CloseAllChilren() hides the window
  852.          * for fewer repaints.
  853.          */
  854.         ShowWindow( hwndMDIClient, SW_SHOW);
  855.  
  856.         break;
  857.  
  858.     default:
  859.        /*
  860.         * This is essential, since there are frame WM_COMMANDS generated
  861.         * by the MDI system for activating child windows via the
  862.         * window menu.
  863.         */
  864.         DefFrameProc(hwnd, hwndMDIClient, WM_COMMAND, wParam, 0L);
  865.     }
  866. }
  867. /****************************************************************************
  868.  *                                        *
  869.  *  FUNCTION   : SetWrap ()                            *
  870.  *                                        *
  871.  *  PURPOSE    : Changes the word wrapping in an edit control. Since this   *
  872.  *         cannot be done by direct means, the function creates a new *
  873.  *         edit control, moves data from the old control to the new   *
  874.  *         control and destroys the original control. Note that the   *
  875.  *         function assumes that the child being modified is currently*
  876.  *         active.                            *        *
  877.  *                                        *
  878.  ****************************************************************************/
  879.  
  880. VOID NEAR PASCAL SetWrap(hwnd, fWrap)
  881. HWND hwnd;
  882. BOOL fWrap;
  883.  
  884. {
  885.     LONG    dws;
  886.     HANDLE  hT;
  887.     HANDLE  hTT;
  888.     HWND    hwndOld;
  889.     HWND    hwndNew;
  890.  
  891.     /* Change word wrap mode */
  892.     SetWindowWord (hwnd, GWW_WORDWRAP, fWrap);
  893.  
  894.     /* Create the appropriate window style, adding a horizontal scroll
  895.      * facility if wrapping is not present.
  896.      */
  897.     dws = WS_CHILD | WS_VSCROLL | ES_AUTOVSCROLL | ES_MULTILINE;
  898.     if (!fWrap)
  899.     dws |= WS_HSCROLL | ES_AUTOHSCROLL;
  900.  
  901.     /* Create a new child window */
  902.     hwndNew = CreateWindow ( "edit",
  903.                  NULL,
  904.                  dws,
  905.                  0,
  906.                  SW_SHOW,
  907.                  0,
  908.                  0,
  909.                  hwnd,
  910.                  ID_EDIT,
  911.                  hInst,
  912.                  NULL);
  913.  
  914.     /* Get handle to current edit control */
  915.     hwndOld = GetWindowWord (hwnd, GWW_HWNDEDIT);
  916.  
  917.     /* Get the data handle of the old control */
  918.     hT = (HANDLE)SendMessage (hwndOld, EM_GETHANDLE, 0, 0L);
  919.  
  920.     /* Create a dummy data handle and make it the handle to
  921.      * the old edit control( hT still references the text of
  922.      * old control).
  923.      */
  924.     hTT = LocalAlloc (LHND, 0);
  925.     SendMessage (hwndOld, EM_SETHANDLE, hTT, 0L);
  926.  
  927.     /* Make the new window the window of interest and destroy the
  928.      * old control.
  929.      */
  930.     SetWindowWord (hwnd, GWW_HWNDEDIT, hwndNew);
  931.     hwndActiveEdit = hwndNew;
  932.     DestroyWindow (hwndOld);
  933.  
  934.     /* Cause the window to be properly sized */
  935.     SendMessage (hwnd, WM_SIZE, 0, 0L);
  936.  
  937.     /* Free the new window's old data handle and set it to
  938.      * hT (text of old edit control)
  939.      */
  940.     LocalFree ((HANDLE)SendMessage (hwndNew, EM_GETHANDLE, 0, 0L));
  941.     SendMessage (hwndNew, EM_SETHANDLE, hT, 0L);
  942.  
  943.     ShowWindow (hwndNew, SW_SHOW);
  944.  
  945.     /* Set focus to the new edit control */
  946.     SetFocus (hwndNew);
  947.  
  948. }
  949.  
  950.  
  951. /****************************************************************************
  952.  *                                        *
  953.  *  FUNCTION   : MPError ( hwnd, flags, id, ...)                *
  954.  *                                        *
  955.  *  PURPOSE    : Flashes a Message Box to the user. The format string is    *
  956.  *         taken from the STRINGTABLE.                    *
  957.  *                                        *
  958.  *  RETURNS    : Returns value returned by MessageBox() to the caller.        *
  959.  *                                        *
  960.  ****************************************************************************/
  961. short FAR MPError (HWND hwnd, WORD bFlags, WORD id, ...)
  962. {
  963.     char sz[160];
  964.     char szFmt[128];
  965.  
  966.     LoadString (hInst, id, szFmt, sizeof (szFmt));
  967.     wvsprintf (sz, szFmt, (LPSTR)(&id + 1));
  968.     LoadString (hInst, IDS_APPNAME, szFmt, sizeof (szFmt));
  969.     return MessageBox (hwndFrame, sz, szFmt, bFlags);
  970. }
  971.  
  972.  
  973. /****************************************************************************
  974.  *                                        *
  975.  *  FUNCTION   : QueryCloseAllChildren()                    *
  976.  *                                        *
  977.  *  PURPOSE    : Asks the child windows if it is ok to close up app. Nothing*
  978.  *         is destroyed at this point. The z-order is not changed.    *
  979.  *                                        *
  980.  *  RETURNS    : TRUE - If all children agree to the query.            *
  981.  *         FALSE- If any one of them disagrees.                *
  982.  *                                        *
  983.  ****************************************************************************/
  984.  
  985. BOOL NEAR PASCAL QueryCloseAllChildren()
  986. {
  987.     register HWND hwndT;
  988.  
  989.     for ( hwndT = GetWindow (hwndMDIClient, GW_CHILD);
  990.       hwndT;
  991.       hwndT = GetWindow (hwndT, GW_HWNDNEXT)       ){
  992.  
  993.     /* Skip if an icon title window */
  994.     if (GetWindow (hwndT, GW_OWNER))
  995.         continue;
  996.  
  997.     if (SendMessage (hwndT, WM_QUERYENDSESSION, 0, 0L))
  998.         return FALSE;
  999.     }
  1000.     return TRUE;
  1001. }
  1002.  
  1003. /****************************************************************************
  1004.  *                                        *
  1005.  *  FUNCTION   : QueryCloseChild (hwnd)                     *
  1006.  *                                        *
  1007.  *  PURPOSE    : If the child MDI is unsaved, allow the user to save, not   *
  1008.  *               save, or cancel the close operation.                       *
  1009.  *                                        *
  1010.  *  RETURNS    : TRUE  - if user chooses save or not save, or if the file   *
  1011.  *                       has not changed.                                   *
  1012.  *         FALSE - otherwise.                        *
  1013.  *                                        *
  1014.  ****************************************************************************/
  1015.  
  1016. BOOL NEAR PASCAL QueryCloseChild(hwnd)
  1017. register HWND hwnd;
  1018. {
  1019.     char     sz [64];
  1020.     register int i;
  1021.  
  1022.     /* Return OK if edit control has not changed. */
  1023.     if (!GetWindowWord (hwnd, GWW_CHANGED))
  1024.     return TRUE;
  1025.  
  1026.     GetWindowText (hwnd, sz, sizeof(sz));
  1027.  
  1028.     /* Ask user whether to save / not save / cancel */
  1029.     i = MPError (hwnd,
  1030.          MB_YESNOCANCEL|MB_ICONQUESTION,IDS_CLOSESAVE,
  1031.          (LPSTR)sz);
  1032.  
  1033.     switch (i){
  1034.     case IDYES:
  1035.         /* User wants file saved */
  1036.         SaveFile(hwnd);
  1037.         break;
  1038.  
  1039.     case IDNO:
  1040.         /* User doesn't want file saved */
  1041.         break;
  1042.  
  1043.     default:
  1044.         /* We couldn't do the messagebox, or not ok to close */
  1045.         return FALSE;
  1046.     }
  1047.     return TRUE;
  1048. }
  1049.